package com.xl.basic.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.xl.basic.entity.Result;
import com.xl.basic.entity.ResultEnums;
import com.xl.basic.entity.param.AddMenuParam;
import com.xl.basic.entity.param.QueryMenuParam;
import com.xl.basic.entity.param.UpdMenuParam;
import com.xl.basic.entity.UserInfo;
import com.xl.basic.enums.BasicRoleEnums;
import com.xl.basic.service.MenuService;
import com.xl.dao.domain.XlMenu;
import com.xl.dao.domain.XlRole;
import com.xl.dao.domain.XlRoleMenu;
import com.xl.dao.mapper.XlMenuMapper;
import com.xl.dao.mapper.XlRoleMapper;
import com.xl.dao.mapper.XlRoleMenuMapper;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.time.LocalDateTime;
import java.util.List;

/**
 * @author 钟勇
 * Create in 2023/8/30 9:06
 */
@Service
@RequiredArgsConstructor
public class MenuServiceImpl implements MenuService {

    private final XlMenuMapper menuMapper;
    private final XlRoleMapper roleMapper;
    private final XlRoleMenuMapper roleMenuMapper;


    @Override
    @Transactional(rollbackFor = Exception.class, timeout = 300)
    public Result<Integer> addMenu(@NonNull AddMenuParam param, UserInfo operator) {
        XlMenu menu = BeanUtil.copyProperties(param, XlMenu.class);
        String operatorUserId = operator == null ? null : operator.getUserId();

        menu.setState(1)
                .setAddTime(LocalDateTime.now())
                .setAddUser(operatorUserId);
        if (menuMapper.insert(menu) <= 0) {
            return ResultEnums.Exception.getResult("菜单新增失败");
        }

        //写入超级管理员权限
        XlRole developerRole = roleMapper.selectOne(new LambdaQueryWrapper<XlRole>()
                .eq(XlRole::getState, 1)
                .eq(XlRole::getRoleSign, BasicRoleEnums.developer.getMenuSign())
                .last("LIMIT 1")
        );

        if (developerRole != null) {
            if (roleMenuMapper.insert(new XlRoleMenu()
                    .setRoleId(developerRole.getRoleId())
                    .setMenuId(menu.getMenuId())
                    .setState(1)
                    .setAddTime(LocalDateTime.now())
                    .setAddUser(operatorUserId)
            ) <= 0) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return ResultEnums.Exception.getResult("权限写入失败");
            }
        }


        return ResultEnums.Success.getDataResult(menu.getMenuId());
    }

    @Override
    public Result<Object> updMenu(@NonNull UpdMenuParam param, UserInfo operator) {
        XlMenu oriMenu = menuMapper.selectById(param.getMenuId());
        if (oriMenu == null || oriMenu.getState() != 1) {
            return ResultEnums.BusinessError.getResult("未找到对应菜单");
        }

        XlMenu menu = BeanUtil.copyProperties(param, XlMenu.class);
        menu.setUpdTime(LocalDateTime.now())
                .setUpdUser(operator == null ? null : operator.getUserId());

        if (menuMapper.updateById(menu) <= 0) {
            return ResultEnums.Exception.getResult("菜单编辑失败");
        }

        return ResultEnums.Success.getResult();
    }

    @Override
    @Transactional(rollbackFor = Exception.class, timeout = 300)
    public Result<Object> delMenu(@NonNull Integer menuId, UserInfo operator) {
        XlMenu oriMenu = menuMapper.selectById(menuId);
        if (oriMenu == null || oriMenu.getState() != 1) {
            return ResultEnums.Success.getResult();
        }

        if (menuMapper.selectCount(new LambdaQueryWrapper<XlMenu>()
                .eq(XlMenu::getState, 1)
                .eq(XlMenu::getParentMenuId, menuId)
        ) > 0) {
            return ResultEnums.BusinessError.getResult("请先移除子菜单");
        }

        XlMenu menu = new XlMenu()
                .setMenuId(menuId)
                .setState(0)
                .setUpdTime(LocalDateTime.now())
                .setUpdUser(operator == null ? null : operator.getUserId());

        if (menuMapper.updateById(menu) <= 0) {
            return ResultEnums.Exception.getResult("菜单删除失败");
        }

        Long roleMenuCount = roleMenuMapper.selectCount(new LambdaQueryWrapper<XlRoleMenu>()
                .eq(XlRoleMenu::getState, 1)
                .eq(XlRoleMenu::getMenuId, menuId)
        );

        if (roleMenuCount > 0) {
            if (roleMenuMapper.update(new XlRoleMenu()
                            .setState(0)
                            .setUpdTime(LocalDateTime.now())
                            .setUpdUser(operator == null ? null : operator.getUserId()),
                    new LambdaUpdateWrapper<XlRoleMenu>()
                            .eq(XlRoleMenu::getState, 1)
                            .eq(XlRoleMenu::getMenuId, menuId)
            ) <= 0) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return ResultEnums.Exception.getResult("角色菜单删除失败");
            }
        }

        return ResultEnums.Success.getResult();
    }

    @Override
    public Result<List<XlMenu>> queryMenuList(@NonNull QueryMenuParam param) {
        List<XlMenu> list = menuMapper.queryMenuList(getQueryWrapper(param));
        return ResultEnums.Success.getListResult(list);
    }

    private Wrapper<XlMenu> getQueryWrapper(@NonNull QueryMenuParam param) {
        QueryWrapper<XlMenu> wrapper = new QueryWrapper<>();
        wrapper.eq("m.state", 1);

        if (param.getRoleId() != null) {
            wrapper.eq("r.role_id", param.getRoleId());
        }

        if (StrUtil.isNotBlank(param.getRoleSign())) {
            wrapper.eq("r.role_sign", param.getRoleSign());
        }

        if (StrUtil.isNotBlank(param.getUserId())) {
            //返回这个用户和公开权限的菜单
            wrapper.and(w -> {
                String pubMenuSign = BasicRoleEnums.pub.getMenuSign();
                w.eq("ru.user_id", param.getUserId());
                w.or();
                w.eq("r.role_sign", pubMenuSign);
            });
        }

        return wrapper;
    }
}
